home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
EditFields
/
EditFields.c
< prev
next >
Wrap
Text File
|
1992-09-10
|
14KB
|
606 lines
/****************************************************************************************
*
*
* Edit Field Library- .h Definition File
*
* 9/9/92 ©ImproVision UK. Written by Graham Cox.
*
****************************************************************************************/
#include "EditFields.h"
extended
GPCstr2num(void *s)
{
short n = 1;
char p = 0;
decimal d;
extended x;
decstr68k(s, &n, &d, &p, FPSTR2DEC);
fp68k(&d, &x, FDEC2X);
return(x);
}
void
GPCnum2str(decform *f, extended x, void *s)
{
decimal d;
fp68k(f, &x, &d, FX2DEC);
decstr68k(f, &d, s, FDEC2STR);
}
CopyString(Ptr s1,Ptr s2)
{
short byteCount;
byteCount=*s1+1;
BlockMove(s1,s2,byteCount);
}
ConcatString(Ptr s1,Ptr s2)
{
/* given pointers to two pascal strings, this function concatenates the characters of
s2 on to the end of s1. No range checking is performed. */
short byteCount,offset;
Ptr temp;
temp=s1; /* remember old pointer */
offset=*s1+1; /* length of first string */
s1+=offset; /* point at end of string +1 */
byteCount=*s2; /* length of second string */
s2++; /* first char of second string */
BlockMove(s2,s1,byteCount); /* copy chars */
*temp=offset+byteCount-1; /* update length */
}
EditFieldHdl NewEditField(Rect *bounds,int IDnum,Str255 *theText)
{
/* creates a new edit field record with the given parameters. The record is not
automatically linked to the fields list- you have to do this */
EditFieldHdl temp;
temp = (EditFieldHdl) NewHandleClear(sizeof(EditField));
if (temp != NIL) {
(*temp)->efID = IDnum;
(*temp)->edViewRect = *bounds;
(*temp)->edFlags = fieldNoRestriction;
(*temp)->upLimit = 256;
(*temp)->lowLimit = 1;
HLock((Handle) temp);
CopyString((Ptr)theText,(Ptr)&(*temp)->edFieldText);
HUnlock((Handle) temp);
(*temp)->nextField = NIL;
}
return(temp);
}
void LinkEditField(EFListHdl efList,EditFieldHdl eField)
{
/* pushes the given eField onto the top of the stack of fields in the main struct */
if (efList != NIL && eField != NIL) {
(*eField)->nextField = (*efList)->efListHead;
(*efList)->efListHead = eField;
}
}
void Draw1Field(EditFieldHdl theField)
{
/* draws the given field using TextBox */
Rect tView,tFrame;
if (theField != NIL) {
tView = (*theField)->edViewRect;
tFrame = tView;
InsetRect(&tFrame,-3,-3);
FrameRect(&tFrame);
HLock((Handle) theField);
TextBox(&(*theField)->edFieldText[1],
(*theField)->edFieldText[0],
&tView,
teJustLeft);
HUnlock((Handle) theField);
}
}
void SetFieldText(EditFieldHdl theField,Str255 *theText)
{
/* sets the text in the given field to the supplied string. To update the display,
you will need to do more! */
if (theField != NIL) {
CopyString((Ptr)theText,(Ptr)&(*theField)->edFieldText);
(*theField)->edFlags |= fieldDataChanged;
}
}
void GetFieldText(EditFieldHdl theField,Str255 *theText)
{
/* returns the string in the associated field */
if (theField != NIL)
CopyString((Ptr)&(*theField)->edFieldText,(Ptr)theText);
}
void SetFPField(EditFieldHdl theField,extended fpValue,int nDecPlaces)
{
/* converts the given floating point value to a string with the given number of
decimal places, then sets the text of the field to this string. */
DecForm fpFormat;
Str255 fpText;
if (theField != NIL) {
fpFormat.style = FIXEDDECIMAL;
fpFormat.digits = nDecPlaces;
GPCnum2str(&fpFormat,fpValue,&fpText);
SetFieldText(theField,&fpText);
}
}
extended GetFPField(EditFieldHdl theField)
{
/* converts the given field's text string to a floating point value. */
Str255 fpText;
if (theField != NIL) {
GetFieldText(theField,&fpText);
return(GPCstr2num(&fpText));
}
}
void SetEdFlags(EditFieldHdl theField,long theFlags)
{
/* sets the flags field to the given value */
if (theField != NIL)
(*theField)->edFlags = theFlags;
}
long GetEdFlags(EditFieldHdl theField)
{
/* returns the field flags field */
if (theField != NIL)
return((*theField)->edFlags);
else
return(-1L);
}
EFListHdl NewEditFieldList(WindowPtr ownerWindow)
{
/* creates a new edit field list record, preinitialised with the owner window, and a
new TERecord incorporating the ownerWindow's grafPort. No fields are yet attached
to the record- these are created with NewEditField and linked with LinkEditField */
EFListHdl temp;
GrafPtr savePort;
Rect tRect;
temp = (EFListHdl)NewHandleClear(sizeof(EFList));
if (temp != NIL) {
(*temp)->efOwner = ownerWindow;
(*temp)->numFields = 0;
(*temp)->currentField = 0;
(*temp)->efListHead = NIL;
GetPort(&savePort);
SetPort(ownerWindow);
tRect = ownerWindow->portRect;
(*temp)->efText = TENew(&tRect,&tRect);
SetPort(savePort);
}
return(temp);
}
void DisposeEditFieldList(EFListHdl theList)
{
/* disposes of ef list and all internal structures */
EditFieldHdl temp,efNext;
if (theList != NIL) {
temp = (*theList)->efListHead;
while (temp != NIL) {
efNext = (*temp)->nextField;
DisposHandle(temp);
temp = efNext;
}
TEDispose((*theList)->efText);
DisposHandle(theList);
}
}
EditFieldHdl GetIndexedField(EFListHdl efList,int theIndex)
{
/* returns the handle of the edit field record having the ID number theIndex. If
the index does not exist in the list, NIL is returned */
EditFieldHdl temp = NIL;
if (efList != NIL) {
temp = (*efList)->efListHead;
while (temp != NIL) {
if ((*temp)->efID == theIndex)
break;
else
temp = (*temp)->nextField;
}
}
return(temp);
}
void IncDecCurrentField(EFListHdl efList,Boolean incDecFlag)
{
/* increment or decrements currently selected edit field. This is designed to be
called repeatedly in a loop, and uses a delay to avoid this occurring too fast. */
long tDelay,fValue,efFlags,uLimit,lLimit;
EditFieldHdl theField;
Str255 fText;
CharsHandle eChars;
TEHandle theText;
DecForm fpFormat;
extended fpValue;
if (efList != NIL) {
theText = (*efList)->efText;
if (theText != NIL) {
TEDeactivate(theText);
eChars = TEGetText(theText);
BlockMove(*eChars,&fText[1],(*theText)->teLength);
fText[0] = (*theText)->teLength;
theField = GetIndexedField(efList,(*efList)->currentField);
if (theField != NIL) {
efFlags = GetEdFlags(theField);
uLimit = (*theField)->upLimit;
lLimit = (*theField)->lowLimit;
if ((efFlags & (fieldNumeric + fieldFloatingPoint + fieldConvertTicks))
== (fieldNumeric + fieldFloatingPoint + fieldConvertTicks)) {
/* need floating point data */
fpFormat.style = FIXEDDECIMAL;
fpFormat.digits = 2;
fpValue = GPCstr2num(&fText);
if (incDecFlag) {
fpValue -= 0.01667;
if ((fpValue * 60) < lLimit)
fpValue = (extended)lLimit/60;
}
else {
fpValue += 0.01667;
if ((fpValue * 60) > uLimit)
fpValue = (extended)uLimit/60;
}
GPCnum2str(&fpFormat,fpValue,&fText);
}
else {
StringToNum(&fText,&fValue);
if (incDecFlag) {
fValue --;
if (fValue < (lLimit +1))
fValue = lLimit;
}
else {
fValue ++;
if (fValue > (uLimit -1))
fValue = uLimit;
}
NumToString(fValue,&fText);
}
TESetText(&fText[1],fText[0],theText);
TEUpdate(&(*theText)->viewRect,theText);
Delay(3,&tDelay);
}
TEActivate(theText);
}
}
}
void DrawEditFields(EFListHdl efList)
{
/* from the given record, draws the edit fields in the current port. The non-selected
fields are updated using TextBox, the selected one updated using TEUpdate */
EditFieldHdl temp;
Rect tView,tFrame;
int eSelect;
if (efList != NIL) {
temp = (*efList)->efListHead;
eSelect = (*efList)->currentField;
while(temp != NIL) {
if ((*temp)->efID == eSelect) {
tView = (*temp)->edViewRect;
tFrame = tView;
InsetRect(&tFrame,-3,-3);
FrameRect(&tFrame);
TEUpdate(&tView,(*efList)->efText);
}
else
Draw1Field(temp);
temp = (*temp)->nextField;
}
}
}
void SelectEditField(EFListHdl efList,int theIndex)
{
/* sets up the text record so that the indexed field is selected for editing. The
text in the existing record is copied out to the field identified by the
edFieldSelected value, the new text copied to the record, and the internal value
updated */
EditFieldHdl oldField,newField;
TEHandle theEdRec;
CharsHandle teText;
int oldIndex;
Rect eView;
GrafPtr savePort;
if (efList != NIL) {
GetPort(&savePort);
SetPort((*efList)->efOwner);
theEdRec = (*efList)->efText;
if (theEdRec != NIL) {
oldIndex = (*efList)->currentField;
oldField = GetIndexedField(efList,oldIndex);
if ((oldField != NIL) && !((*oldField)->edFlags & fieldDataChanged)) {
teText = TEGetText(theEdRec);
HLock((Handle) oldField);
BlockMove(*teText,&(*oldField)->edFieldText[1],(*theEdRec)->teLength);
(*oldField)->edFieldText[0] = (*theEdRec)->teLength;
HUnlock((Handle) oldField);
}
if ((oldIndex != theIndex) || ((*oldField)->edFlags & fieldDataChanged)) {
TEDeactivate(theEdRec);
newField = GetIndexedField(efList,theIndex);
(*newField)->edFlags &= (0xFFFFFFFF - fieldDataChanged);
if (newField != NIL) {
(*efList)->currentField = theIndex;
HLock((Handle) newField);
TESetText(&(*newField)->edFieldText[1],
(*newField)->edFieldText[0],theEdRec);
HUnlock((Handle) newField);
eView = (*newField)->edViewRect;
(*theEdRec)->destRect = eView;
(*theEdRec)->viewRect = eView;
(*theEdRec)->destRect.right += 256;
TECalText(theEdRec);
Draw1Field(newField);
}
TEActivate(theEdRec);
}
}
SetPort(savePort);
}
}
int FindEditField(EFListHdl efList,Point mClick)
{
/* returns the ID number of the edit field containing the point, or zero if none do.
This is used to hit test the edit fields when the window is clicked */
EditFieldHdl eField;
Rect efRect;
int efClicked = 0;
if (efList != NIL) {
eField = (*efList)->efListHead;
while (eField != NIL) {
efRect = (*eField)->edViewRect;
InsetRect(&efRect,-2,-2);
if (PtInRect(mClick,&efRect)) {
efClicked = (*eField)->efID;
break;
}
else
eField = (*eField)->nextField;
}
}
return(efClicked);
}
void EFIdle(EFListHdl efList)
{
/* call frequently to blink the caret in edit fields */
if (efList != NIL)
TEIdle((*efList)->efText);
}
int CheckFieldLimits(EditFieldHdl theField,EFListHdl efList)
{
/* gets the current field value, if numeric, and checks it's current setting against
the bounds. If outside, the value is changed to be pinned to the bounds */
long fValue,efFlags,uLimit,lLimit;
extended fValueFP;
Str255 fText;
int efsSave;
if (theField != NIL && efList != NIL) {
efFlags = GetEdFlags(theField);
efsSave = (*efList)->currentField;
if (efsSave == (*theField)->efID)
SelectEditField(efList,efsSave); /* ensure field valid */
if (efFlags & fieldNumeric) {
if (efFlags & fieldFloatingPoint) {
fValueFP = GetFPField(theField);
if (efFlags & fieldConvertTicks)
fValue = (fValueFP + 0.02) * 60;
else
fValue = fValueFP;
}
else {
GetFieldText(theField,&fText);
StringToNum(&fText,&fValue);
}
uLimit = (*theField)->upLimit;
lLimit = (*theField)->lowLimit;
if (fValue > uLimit) {
fValue = uLimit;
SetAndUpdateField(efList,(*theField)->efID,fValue);
SysBeep(1);
TESetSelect(0,32767,(*efList)->efText);
return(FALSE);
}
else {
if (fValue < lLimit) {
fValue = lLimit;
SetAndUpdateField(efList,(*theField)->efID,fValue);
SysBeep(1);
TESetSelect(0,32767,(*efList)->efText);
return(FALSE);
}
}
}
}
return(TRUE);
}
void KeyField(EFListHdl efList,char theKey)
{
/* passes keys to the current field. This examines the flags of the field to deter-
mine what characters are filtered out. Control keys must already have been
filtered and dealt with */
int efSelect;
EditFieldHdl eField;
long efFlags;
Boolean charInRange;
if (efList != NIL) {
efSelect = (*efList)->currentField;
eField = GetIndexedField(efList,efSelect);
efFlags = GetEdFlags(eField);
if (theKey == 0x08 || (theKey >= 0x1C && theKey <= 0x1F))
TEKey(theKey,(*efList)->efText);
else {
if (efFlags != fieldNoRestriction) {
if (efFlags & fieldNumeric) {
charInRange = !(theKey < 0x30 || theKey > 0x39);
if (efFlags & fieldFloatingPoint)
charInRange = charInRange || (theKey == 0x2E);
}
else {
if (efFlags & fieldAlphabetic)
charInRange = !(theKey < 0x41 || theKey > 0x7A);
}
if (charInRange)
TEKey(theKey,(*efList)->efText);
else
SysBeep(1);
}
else
TEKey(theKey,(*efList)->efText);
}
}
}
void SetAndUpdateField(EFListHdl efList,int theFieldID,long fValue)
{
/* given a fieldID number and a value, the value is converted to a string, set into
the identified field (if it exists!) and the whole caboodle is updated. */
Str255 fText;
EditFieldHdl theField;
int saveSelect;
long efFlags;
extended fValueFP;
if (efList != NIL) {
theField = GetIndexedField(efList,theFieldID);
if (theField != NIL) {
efFlags = GetEdFlags(theField);
saveSelect = (*efList)->currentField;
if ((efFlags & (fieldNumeric + fieldFloatingPoint))
== (fieldNumeric + fieldFloatingPoint)) {
if (efFlags & fieldConvertTicks)
fValueFP = (extended)fValue/60;
else
fValueFP = (extended)fValue;
SetFPField(theField,fValueFP,2);
}
else {
NumToString(fValue,&fText);
SetFieldText(theField,&fText);
}
(*efList)->currentField = 0; /* fudge the update mechanism! */
SelectEditField(efList,theFieldID); /* keep text in order & update */
SelectEditField(efList,saveSelect); /* restore the old field selection */
}
}
}